package com.bosssoft.gateway.authorization.serve.service.impl;

import com.bosssoft.gateway.authorization.serve.service.RenewTokenService;
import com.bosssoft.gateway.authorization.serve.service.constant.BusinessResultConsts;
import common.exception.code.BizErrorCode;
import common.exception.parse.BusinessException;
import common.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.Date;

/**
 * @className: RenewTokenServiceImpl
 * @description: 解决什么问题：
 * 演示线程池的正确使用
 * 主要方法：
 * methodxx 使用 ThreadPoolExecutor创建线程进行任务操作
 * 注意事项：
 * 例如：该类需要从容器获取不可以new
 * @author: lanyukai
 * @date: 2024/6/18 23:19
 * @since 1.0
 **/
@Service
public class RenewTokenServiceImpl implements RenewTokenService {
    //    @Value("${app.secret.token.key}")
    private String secret = "$6$bosssoft$";
    /**
     * 默认设置10天的token有效期
     */
//    @Value("${app.secret.token.period}")
    private Long period = 864000L;
    /**
     * 默认设置一天的提前提醒时间 举例如果有效期10天则在第9天提醒
     */
//    @Value("${app.secret.token.remind}")
    private Long remind = 1000L;
    /**
     * 续期时间三天 单位毫秒 1000 * 60 * 60 * 24 * 3 = 86400
     */
    private static final Long p = 259200000L;

    private static final String TOKEN_USER_ID_KEY = "user";

    /**
     * 操作redis token
     */
    @Resource(name = "AuthorizationTokenRedisTemplate")
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public String renewToken(String userId) {
        Assert.hasText(userId, "userId为空, renewToken()参数异常");
        // 从redis中获取token 是整个jwt token的 JSONString 格式
        Object tokenString = redisTemplate.opsForValue().get(TOKEN_USER_ID_KEY + userId);
        if (ObjectUtils.isEmpty(tokenString)) {
            throw new BusinessException(BizErrorCode.DATA_SEARCH_NOT_FOUND,
                    String.format("无法通过key=%s 从缓存找到token", userId));
        }
        // 更新 更新 token的 过期时间
        Claims jwtTokenItemList = JwtUtil.parseToken(String.valueOf(tokenString));
        updateTokenPayloadExpiresAt(jwtTokenItemList);
        // 重新签名token
        String signatureToken = JwtUtil.generateToken(jwtTokenItemList);
        // 重新更新 redis token
        redisTemplate.opsForValue().set(TOKEN_USER_ID_KEY + userId, signatureToken);
        // 返回新的token
        return signatureToken;

    }

    @Override
    public int expire(Long userId, String token) {
        Object jwtToken = redisTemplate.opsForValue().get(TOKEN_USER_ID_KEY + userId);
        System.out.println(jwtToken);
        if (ObjectUtils.isEmpty(jwtToken)) {
            // 返回过期 前端根据这个需要重新登录
            return BusinessResultConsts.TOKEN_EXPIRE_TURE;
        } else {
            // 解析token 比较过期时间 和 当前时间
            Claims joPayload = JwtUtil.parseToken(token);
            // 取决认证服务放进去的是什么类型
            Long expiresTime = Long.parseLong(String.valueOf(joPayload.get("iat")));
            // remind 为 配置文件设置的提醒到期的时间 *1000为微妙毫秒

                // 没有到过期时间 还处在有效期
                return BusinessResultConsts.TOKEN_EXPIRE_FALSE;
            }

    }

    /**
     * 更新过期时间用于重新计算token签名
     *
     * @param payload JWT 的 payload部分
     * @return payload
     */
    private Claims updateTokenPayloadExpiresAt(Claims payload) {
        Assert.notNull(payload, "payload updateTokenExpiresAt参数错误");
        payload.put("iat", new Date(System.currentTimeMillis() + period * 1000));
        return payload;
    }
}
